from rest_framework import status, generics, viewsets, mixins
from rest_framework import status, generics, viewsets, mixins
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.decorators import api_view, action
from rest_framework.permissions import IsAuthenticated, IsAuthenticatedOrReadOnly, AllowAny
from rest_framework.authentication import SessionAuthentication, TokenAuthentication
from rest_framework_simplejwt.authentication import JWTAuthentication
from rest_framework.filters import SearchFilter, OrderingFilter
from rest_framework.parsers import MultiPartParser, FormParser
from django_filters.rest_framework import DjangoFilterBackend
from django.shortcuts import get_object_or_404
from django.db.models import Q
from django.http import HttpResponse
from PIL import Image, ImageOps
import io

from .models import Category, Product, Review, Tag, ProductTag
from .serializers import (
    CategorySerializer, CategoryManualSerializer,
    ProductDetailSerializer, ProductListSerializer,
    ProductCreateUpdateSerializer, ReviewSerializer,
    TagSerializer, ProductTagSerializer,
    DynamicProductSerializer, ProductReadOnlySerializer,
    HyperlinkedCategorySerializer, UserSerializer,
    ProductImageUploadSerializer, ProductImageSerializer
)


# ==================== API 根视图 ====================
class APIRootView(APIView):
    """
    DRF学习项目 API 根目录
    提供所有可用API端点的概览
    """
    permission_classes = [AllowAny]

    def get(self, request, format=None):
        """返回API端点列表"""
        return Response({
            'message': '欢迎使用 DRF 学习项目 API',
            'version': 'v1.0',
            'description': '这是一个用于学习Django REST Framework的示例项目',
            'endpoints': {
                '认证': {
                    'JWT Token': request.build_absolute_uri('/api/auth/token/'),
                    'Token刷新': request.build_absolute_uri('/api/auth/token/refresh/'),
                },
                '分类管理': {
                    'APIView实现': request.build_absolute_uri('/api/categories/basic/'),
                    '函数视图实现': request.build_absolute_uri('/api/categories/function/'),
                },
                '产品管理': {
                    'Generic Views': request.build_absolute_uri('/api/products/generic/'),
                    'Custom Mixins': request.build_absolute_uri('/api/products/custom/'),
                    'ViewSet (完整)': request.build_absolute_uri('/api/v1/products/'),
                    'ViewSet (简单)': request.build_absolute_uri('/api/simple/simple-products/'),
                    '手动路由': request.build_absolute_uri('/api/manual/products/'),
                    '统计分析': request.build_absolute_uri('/api/products/stats/'),
                },
                '图片处理': {
                    '图片上传': request.build_absolute_uri('/api/products/1/upload-image/'),
                    '图片缩放': request.build_absolute_uri('/api/products/1/resize-image/'),
                    '图片信息': request.build_absolute_uri('/api/products/1/image-info/'),
                    '缩略图': request.build_absolute_uri('/api/products/1/thumbnail/'),
                },
                '其他资源': {
                    '标签管理': request.build_absolute_uri('/api/v1/tags/'),
                    '评论管理': request.build_absolute_uri('/api/v1/reviews/'),
                    '分类只读': request.build_absolute_uri('/api/v1/categories-readonly/'),
                    '批量操作': request.build_absolute_uri('/api/v1/products-bulk/'),
                }
            },
            'documentation': {
                'Swagger': request.build_absolute_uri('/swagger/'),
                'ReDoc': request.build_absolute_uri('/redoc/'),
                'DRF 浏览器': request.build_absolute_uri('/api-auth/'),
            },
            'features': [
                '10种不同的视图实现方式',
                '10种不同的序列化器类型',
                'JWT 和 Session 认证',
                '权限控制和过滤搜索',
                'Pillow 图片处理',
                '完整的测试用例'
            ]
        })


# ==================== 1. 基础APIView实现 ====================
class CategoryListAPIView(APIView):
    """
    基础APIView实现 - 手动处理所有HTTP方法
    优点: 完全控制，灵活性最高
    缺点: 代码量大，需要手动处理分页、过滤等
    """
    permission_classes = [AllowAny]

    def get(self, request):
        """获取分类列表"""
        categories = Category.objects.all()
        serializer = CategorySerializer(categories, many=True)
        return Response(serializer.data)

    def post(self, request):
        """创建新分类"""
        serializer = CategorySerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)


class CategoryDetailAPIView(APIView):
    """分类详情APIView - 处理单个对象的CRUD"""
    permission_classes = [IsAuthenticatedOrReadOnly]

    def get_object(self, pk):
        return get_object_or_404(Category, pk=pk)

    def get(self, request, pk):
        """获取分类详情"""
        category = self.get_object(pk)
        serializer = CategorySerializer(category)
        return Response(serializer.data)

    def put(self, request, pk):
        """更新分类"""
        category = self.get_object(pk)
        serializer = CategorySerializer(category, data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    def delete(self, request, pk):
        """删除分类"""
        category = self.get_object(pk)
        category.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)


# ==================== 2. 函数式视图 ====================
@api_view(['GET', 'POST'])
def category_list_function_view(request):
    """
    函数式视图实现
    优点: 简单直接，适合简单逻辑
    缺点: 不易扩展，缺乏面向对象的优势
    """
    if request.method == 'GET':
        categories = Category.objects.all()
        serializer = CategoryManualSerializer(categories, many=True)
        return Response(serializer.data)

    elif request.method == 'POST':
        serializer = CategoryManualSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)


# ==================== 3. Generic Views ====================
class ProductListCreateView(generics.ListCreateAPIView):
    """
    ListCreateAPIView - 用于列表展示和创建
    优点: 代码简洁，自动处理分页、过滤
    缺点: 灵活性相对较低
    """
    queryset = Product.objects.all()
    permission_classes = [IsAuthenticatedOrReadOnly]
    filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
    filterset_fields = ['category', 'status', 'created_by']
    search_fields = ['name', 'description']
    ordering_fields = ['created_at', 'price', 'name']
    ordering = ['-created_at']

    def get_serializer_class(self):
        """根据请求类型选择不同的序列化器"""
        if self.request.method == 'POST':
            return ProductCreateUpdateSerializer
        return ProductListSerializer

    def perform_create(self, serializer):
        """创建时自动设置创建者"""
        serializer.save(created_by=self.request.user)


class ProductRetrieveUpdateDestroyView(generics.RetrieveUpdateDestroyAPIView):
    """
    RetrieveUpdateDestroyAPIView - 处理单个对象的详情、更新、删除
    """
    queryset = Product.objects.select_related('category', 'created_by').prefetch_related('reviews__reviewer')
    permission_classes = [IsAuthenticatedOrReadOnly]

    def get_serializer_class(self):
        """根据请求类型选择不同的序列化器"""
        if self.request.method in ['PUT', 'PATCH']:
            return ProductCreateUpdateSerializer
        return ProductDetailSerializer


# ==================== 4. Generic Views + Mixins ====================
class CustomProductView(mixins.ListModelMixin,
                       mixins.CreateModelMixin,
                       mixins.RetrieveModelMixin,
                       mixins.UpdateModelMixin,
                       mixins.DestroyModelMixin,
                       generics.GenericAPIView):
    """
    自定义组合Mixins - 完全控制每个操作
    优点: 灵活组合功能，可自定义每个方法
    缺点: 需要手动定义HTTP方法映射
    """
    queryset = Product.objects.all()
    serializer_class = ProductDetailSerializer
    permission_classes = [IsAuthenticatedOrReadOnly]

    def get(self, request, *args, **kwargs):
        """GET请求路由"""
        if 'pk' in kwargs:
            return self.retrieve(request, *args, **kwargs)
        return self.list(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        """创建对象"""
        return self.create(request, *args, **kwargs)

    def put(self, request, *args, **kwargs):
        """更新对象"""
        return self.update(request, *args, **kwargs)

    def patch(self, request, *args, **kwargs):
        """部分更新对象"""
        return self.partial_update(request, *args, **kwargs)

    def delete(self, request, *args, **kwargs):
        """删除对象"""
        return self.destroy(request, *args, **kwargs)


# ==================== 5. ModelViewSet ====================
class ProductModelViewSet(viewsets.ModelViewSet):
    """
    ModelViewSet - 最完整的ViewSet，包含所有CRUD操作
    优点: 功能完整，代码最少，自动路由
    缺点: 可能包含不需要的功能
    """
    queryset = Product.objects.select_related('category', 'created_by').prefetch_related('reviews')
    permission_classes = [IsAuthenticatedOrReadOnly]
    filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
    filterset_fields = ['category', 'status', 'created_by']
    search_fields = ['name', 'description']
    ordering_fields = ['created_at', 'price', 'name']

    def get_serializer_class(self):
        """根据动作选择不同的序列化器"""
        if self.action == 'list':
            return ProductListSerializer
        elif self.action in ['create', 'update', 'partial_update']:
            return ProductCreateUpdateSerializer
        return ProductDetailSerializer

    def perform_create(self, serializer):
        """创建时设置创建者"""
        serializer.save(created_by=self.request.user)

    @action(detail=True, methods=['get'])
    def reviews(self, request, pk=None):
        """自定义动作: 获取产品评论"""
        product = self.get_object()
        reviews = product.reviews.all()
        serializer = ReviewSerializer(reviews, many=True)
        return Response(serializer.data)

    @action(detail=True, methods=['post'], permission_classes=[IsAuthenticated])
    def add_review(self, request, pk=None):
        """自定义动作: 添加产品评论"""
        product = self.get_object()
        serializer = ReviewSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save(product=product, reviewer=request.user)
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    @action(detail=False, methods=['get'])
    def my_products(self, request):
        """自定义动作: 获取我创建的产品"""
        products = self.queryset.filter(created_by=request.user)
        serializer = self.get_serializer(products, many=True)
        return Response(serializer.data)


# ==================== 6. ReadOnlyModelViewSet ====================
class CategoryReadOnlyViewSet(viewsets.ReadOnlyModelViewSet):
    """
    ReadOnlyModelViewSet - 只读ViewSet，只提供list和retrieve
    优点: 适合只读场景，安全
    缺点: 功能有限，不支持修改操作
    """
    queryset = Category.objects.prefetch_related('products')
    serializer_class = HyperlinkedCategorySerializer
    permission_classes = [AllowAny]
    filter_backends = [SearchFilter, OrderingFilter]
    search_fields = ['name', 'description']
    ordering = ['name']

    @action(detail=True, methods=['get'])
    def products(self, request, pk=None):
        """获取分类下的所有产品"""
        category = self.get_object()
        products = category.products.all()
        serializer = ProductListSerializer(products, many=True)
        return Response(serializer.data)


# ==================== 7. 自定义ViewSet ====================
class CustomTagViewSet(viewsets.GenericViewSet):
    """
    自定义ViewSet - 继承GenericViewSet，手动添加需要的功能
    优点: 完全控制功能，只提供需要的方法
    缺点: 需要手动实现每个方法
    """
    queryset = Tag.objects.all()
    serializer_class = TagSerializer
    permission_classes = [IsAuthenticatedOrReadOnly]

    def list(self, request):
        """列出所有标签"""
        tags = self.get_queryset()
        serializer = self.get_serializer(tags, many=True)
        return Response(serializer.data)

    def create(self, request):
        """创建标签"""
        serializer = self.get_serializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    def retrieve(self, request, pk=None):
        """获取单个标签"""
        tag = get_object_or_404(Tag, pk=pk)
        serializer = self.get_serializer(tag)
        return Response(serializer.data)

    @action(detail=False, methods=['get'])
    def popular(self, request):
        """自定义动作: 获取热门标签（使用次数多的）"""
        # 这里可以添加复杂的查询逻辑
        popular_tags = Tag.objects.all()[:10]  # 简化示例
        serializer = self.get_serializer(popular_tags, many=True)
        return Response(serializer.data)


# ==================== 8. 混合多种认证和权限 ====================
class ReviewViewSet(viewsets.ModelViewSet):
    """
    评论ViewSet - 演示复杂的权限控制
    """
    serializer_class = ReviewSerializer
    authentication_classes = [JWTAuthentication, SessionAuthentication]

    def get_permissions(self):
        """根据动作设置不同的权限"""
        if self.action in ['list', 'retrieve']:
            permission_classes = [AllowAny]
        elif self.action == 'create':
            permission_classes = [IsAuthenticated]
        else:  # update, partial_update, destroy
            permission_classes = [IsAuthenticated]
        return [permission() for permission in permission_classes]

    def get_queryset(self):
        """动态查询集 - 根据用户权限返回不同数据"""
        if self.request.user.is_authenticated:
            if self.action in ['update', 'partial_update', 'destroy']:
                # 只能操作自己的评论
                return Review.objects.filter(reviewer=self.request.user)
        return Review.objects.all()

    def perform_create(self, serializer):
        """创建时自动设置评论者"""
        product_id = self.request.data.get('product')
        product = get_object_or_404(Product, pk=product_id)
        serializer.save(reviewer=self.request.user, product=product)


# ==================== 9. 批量操作ViewSet ====================
class ProductBulkViewSet(viewsets.ModelViewSet):
    """
    支持批量操作的ProductViewSet
    演示如何处理批量创建、更新、删除
    """
    queryset = Product.objects.all()
    serializer_class = ProductDetailSerializer
    permission_classes = [IsAuthenticated]

    @action(detail=False, methods=['post'])
    def bulk_create(self, request):
        """批量创建产品"""
        serializer = ProductCreateUpdateSerializer(data=request.data, many=True)
        if serializer.is_valid():
            products = []
            for item in serializer.validated_data:
                item['created_by'] = request.user
                products.append(Product(**item))
            Product.objects.bulk_create(products)
            return Response({'message': f'成功创建 {len(products)} 个产品'})
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    @action(detail=False, methods=['patch'])
    def bulk_update(self, request):
        """批量更新产品状态"""
        product_ids = request.data.get('ids', [])
        update_data = request.data.get('data', {})

        if not product_ids or not update_data:
            return Response({'error': '需要提供产品ID列表和更新数据'},
                          status=status.HTTP_400_BAD_REQUEST)

        updated = Product.objects.filter(
            id__in=product_ids,
            created_by=request.user
        ).update(**update_data)

        return Response({'message': f'成功更新 {updated} 个产品'})

    @action(detail=False, methods=['delete'])
    def bulk_delete(self, request):
        """批量删除产品"""
        product_ids = request.data.get('ids', [])

        if not product_ids:
            return Response({'error': '需要提供产品ID列表'},
                          status=status.HTTP_400_BAD_REQUEST)

        deleted_count, _ = Product.objects.filter(
            id__in=product_ids,
            created_by=request.user
        ).delete()

        return Response({'message': f'成功删除 {deleted_count} 个产品'})


# ==================== 10. 统计和分析视图 ====================
class ProductStatsAPIView(APIView):
    """
    产品统计API - 演示复杂查询和数据分析
    """
    permission_classes = [IsAuthenticated]

    def get(self, request):
        """获取产品统计信息"""
        from django.db.models import Count, Avg, Sum

        stats = {
            'total_products': Product.objects.count(),
            'products_by_status': dict(
                Product.objects.values('status').annotate(count=Count('id'))
                .values_list('status', 'count')
            ),
            'products_by_category': list(
                Category.objects.annotate(
                    product_count=Count('products')
                ).values('name', 'product_count')
            ),
            'average_price': Product.objects.aggregate(Avg('price'))['price__avg'] or 0,
            'total_stock': Product.objects.aggregate(Sum('stock'))['stock__sum'] or 0,
            'recent_products': ProductListSerializer(
                Product.objects.order_by('-created_at')[:5],
                many=True
            ).data,
        }

        # 用户相关统计
        if request.user.is_authenticated:
            stats['my_products_count'] = Product.objects.filter(
                created_by=request.user
            ).count()
            stats['my_reviews_count'] = Review.objects.filter(
                reviewer=request.user
            ).count()

        return Response(stats)


# ==================== 11. 图片处理相关视图 ====================
class ProductImageUploadAPIView(APIView):
    """
    产品图片上传API - 演示Pillow图片处理功能
    支持图片上传、验证、压缩和缩略图生成
    """
    permission_classes = [IsAuthenticated]
    parser_classes = [MultiPartParser, FormParser]

    def post(self, request, pk):
        """上传产品图片"""
        product = get_object_or_404(Product, pk=pk, created_by=request.user)

        serializer = ProductImageUploadSerializer(product, data=request.data, partial=True)
        if serializer.is_valid():
            # 保存原始图片
            serializer.save()

            # 生成缩略图
            if product.image:
                self.generate_thumbnail(product)

            # 返回图片信息
            image_serializer = ProductImageSerializer(product, context={'request': request})
            return Response(image_serializer.data, status=status.HTTP_200_OK)

        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    def generate_thumbnail(self, product):
        """生成产品图片缩略图"""
        try:
            with Image.open(product.image.path) as img:
                # 自动调整图片方向
                img = ImageOps.exif_transpose(img)

                # 生成不同尺寸的缩略图
                thumbnail_sizes = [(150, 150), (300, 300), (600, 600)]

                for size in thumbnail_sizes:
                    # 创建缩略图
                    thumbnail = img.copy()
                    thumbnail.thumbnail(size, Image.Resampling.LANCZOS)

                    # 保存缩略图
                    thumb_path = product.image.path.replace(
                        '.', f'_thumb_{size[0]}x{size[1]}.'
                    )
                    thumbnail.save(thumb_path, optimize=True, quality=85)

        except Exception as e:
            print(f"生成缩略图失败: {e}")


class ProductImageResizeAPIView(APIView):
    """
    图片压缩和调整尺寸API - 演示Pillow的高级图片处理功能
    """
    permission_classes = [IsAuthenticated]

    def post(self, request, pk):
        """压缩和调整产品图片"""
        product = get_object_or_404(Product, pk=pk, created_by=request.user)

        if not product.image:
            return Response({'error': '产品没有图片'}, status=status.HTTP_400_BAD_REQUEST)

        # 获取参数
        max_width = int(request.data.get('max_width', 800))
        max_height = int(request.data.get('max_height', 600))
        quality = int(request.data.get('quality', 85))

        try:
            # 打开原始图片
            with Image.open(product.image.path) as img:
                # 自动调整图片方向
                img = ImageOps.exif_transpose(img)

                # 计算新尺寸
                original_width, original_height = img.size
                ratio = min(max_width / original_width, max_height / original_height)

                if ratio < 1:  # 只有当图片需要缩小时才处理
                    new_width = int(original_width * ratio)
                    new_height = int(original_height * ratio)

                    # 调整尺寸
                    resized_img = img.resize((new_width, new_height), Image.Resampling.LANCZOS)

                    # 保存压缩后的图片
                    output = io.BytesIO()
                    format = img.format or 'JPEG'
                    resized_img.save(output, format=format, optimize=True, quality=quality)

                    # 更新产品图片
                    from django.core.files.base import ContentFile
                    content = ContentFile(output.getvalue())
                    product.image.save(
                        product.image.name,
                        content,
                        save=True
                    )

                    return Response({
                        'message': '图片压缩成功',
                        'original_size': f'{original_width}x{original_height}',
                        'new_size': f'{new_width}x{new_height}',
                        'compression_ratio': f'{ratio:.2f}'
                    })
                else:
                    return Response({'message': '图片无需压缩'})

        except Exception as e:
            return Response({'error': f'图片处理失败: {str(e)}'},
                          status=status.HTTP_500_INTERNAL_SERVER_ERROR)


class ProductImageInfoAPIView(APIView):
    """
    获取产品图片详细信息API - 演示Pillow的图片分析功能
    """
    permission_classes = [AllowAny]

    def get(self, request, pk):
        """获取产品图片详细信息"""
        product = get_object_or_404(Product, pk=pk)

        if not product.image:
            return Response({'error': '产品没有图片'}, status=status.HTTP_404_NOT_FOUND)

        try:
            with Image.open(product.image.path) as img:
                # 获取图片基本信息
                info = {
                    'filename': product.image.name,
                    'size': product.image.size,
                    'width': img.width,
                    'height': img.height,
                    'format': img.format,
                    'mode': img.mode,
                    'has_transparency': img.mode in ('RGBA', 'LA', 'P'),
                }

                # 获取EXIF信息
                if hasattr(img, '_getexif') and img._getexif():
                    exif = img._getexif()
                    if exif:
                        # 提取常用EXIF信息
                        info['exif'] = {
                            'datetime': exif.get(306),  # DateTime
                            'camera_make': exif.get(271),  # Make
                            'camera_model': exif.get(272),  # Model
                            'orientation': exif.get(274),  # Orientation
                        }

                # 计算图片复杂度（基于颜色数量）
                try:
                    colors = img.convert('RGB').getcolors(maxcolors=256*256*256)
                    if colors:
                        info['color_count'] = len(colors)
                        info['is_simple'] = len(colors) < 256
                except:
                    pass

                # 生成图片URL
                if request:
                    info['url'] = request.build_absolute_uri(product.image.url)

                return Response(info)

        except Exception as e:
            return Response({'error': f'读取图片信息失败: {str(e)}'},
                          status=status.HTTP_500_INTERNAL_SERVER_ERROR)


class ProductImageThumbnailAPIView(APIView):
    """
    生成产品图片缩略图API - 实时生成不同尺寸的缩略图
    """
    permission_classes = [AllowAny]

    def get(self, request, pk):
        """生成并返回缩略图"""
        product = get_object_or_404(Product, pk=pk)

        if not product.image:
            return Response({'error': '产品没有图片'}, status=status.HTTP_404_NOT_FOUND)

        # 获取参数
        width = int(request.GET.get('width', 150))
        height = int(request.GET.get('height', 150))

        # 限制尺寸范围
        width = max(50, min(width, 1000))
        height = max(50, min(height, 1000))

        try:
            with Image.open(product.image.path) as img:
                # 自动调整图片方向
                img = ImageOps.exif_transpose(img)

                # 生成缩略图
                thumbnail = img.copy()
                thumbnail.thumbnail((width, height), Image.Resampling.LANCZOS)

                # 创建响应
                response = HttpResponse(content_type='image/jpeg')
                thumbnail.save(response, 'JPEG', quality=85, optimize=True)

                # 设置缓存头
                response['Cache-Control'] = 'public, max-age=3600'
                response['Content-Disposition'] = f'inline; filename="thumb_{width}x{height}.jpg"'

                return response

        except Exception as e:
            return Response({'error': f'生成缩略图失败: {str(e)}'},
                          status=status.HTTP_500_INTERNAL_SERVER_ERROR)
